#include "../inc/Button.h"

#ifndef NULL
#define NULL ((void *)0)
#endif

/**
 * @brief 按钮参数初始化
 * @param button 按钮对象
 * @param getButtonState 获取按钮状态回调函数
 */
void ButtonInit(Button *button, GetButtonState getButtonState)
{
	button->pressTimes = 0;
	button->tick = 0;
	button->event = 0;
	button->lastState = ButtonFalse;
	button->state = ButtonFalse;
	button->eventTrig = ButtonFalse;
	button->longPressRepeatTime = CONFIG_DEFAULT_LONG_PRESS_REPEAT_TIME;
	button->getState = getButtonState;
}

/**
 * @brief 设置长按重复时间
 * @param t 长按重复事件时间，单位ms，最小为60
 */
void ButtonSetLongPressRepeatTime(Button *button, uint16_t t)
{
	if (t < 60)
		t = 60;

	button->longPressRepeatTime = t;
}

/**
 * @brief 事件判断
 * @retval 返回产生的事件
 */
uint8_t ButtonHandler(Button *button)
{
	if (button->getState == NULL)
		return ButtonEventNone;

	button->state = button->getState();
	if (button->lastState != button->state)
	{
		button->lastState = button->state;

		if (button->state)
		{
			button->pressTimes++;
			return ButtonEventPressTrig; // 按下触发事件
		}

		return ButtonEventReleaseTrig; // 松开触发事件
	}

	if (button->event >= ButtonEventLongPressed) // 上次事件为长按或长按触发
	{
		if (button->state) // 按键仍然按下
		{
			if (++button->tick == button->longPressRepeatTime / ButtonTick)
			{
				button->tick = 0;
				button->event = ButtonEventLongPressRepeat; // 长按重复事件
				button->eventTrig = ButtonTrue;
			}
		}
		else // 按键已松开
		{
			button->tick = 0;
			button->event = ButtonEventNone; // 设置为无事件状态
		}
	}
	else if (button->state != ButtonFalse) // 当前为无事件状态且按键出于按下状态
	{
		// 当保持按下状态时长大于长按触发阈值后，判断为长按
		if (++button->tick >= CONFIG_DEFAULT_LONG_PRESS_TRIG_TIME / ButtonTick)
		{
			button->event = ButtonEventLongPressed;
			button->eventTrig = ButtonTrue;
			button->tick = 0; // 清除tick计数
			button->pressTimes = 0;
		}
	}
	else if (button->tick != 0) // 若开始计时后，1S内按键有松开
	{
		// 根据0.3S内按下的次数来判断单击和双击
		if (++button->tick >= 300 / ButtonTick)
		{
			switch (button->pressTimes)
			{
			case 1: // 单击事件
				button->event = ButtonEventClicked;
				button->eventTrig = ButtonTrue;
				break;
			case 2: // 双击事件
				button->event = ButtonEventDClicked;
				button->eventTrig = ButtonTrue;
				break;
			}

			button->tick = 0; // 清除tick计数
			button->pressTimes = 0;
		}
	}

	if (button->eventTrig && button->event != ButtonEventNone) // 若有事件发生
	{
		button->eventTrig = ButtonFalse; // 标记事件触发完毕
		return button->event;			 // 返回事件
	}

	return ButtonEventNone;
}
